package se.devoteam.nexus.ldap;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.jsecurity.realm.ldap.LdapContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A <code>LdapContextFactory</code> implementation that creates LDAP contexts based
 * on the LDAP realm configuration.
 * 
 * @author Anders Hammar
 */
@Component(role = LdapContextFactory.class)
public class NexusLdapContextFactory implements LdapContextFactory {

	private final Logger logger = LoggerFactory.getLogger(NexusLdapContextFactory.class);

	@Requirement
	private LdapConfigurationManager configuration;

	protected Logger getLogger() {
		return logger;
	}

	public LdapContext getLdapContext(String username, String password) throws NamingException {
		String providerUrl = this.configuration.getProviderUrl();
		String ctxFactoryClassName = this.configuration.getInitialContextFactory();
		String securityProtocol = this.configuration.getSecurityProtocol();
		String securityAuthentication = this.configuration.getSecurityAuthentication();
		String referral = this.configuration.getReferral();

		if (getLogger().isDebugEnabled()) {
			getLogger().debug("LDAP provider url(s): {}", providerUrl);
			getLogger().debug("LDAP initial context factory: {}", ctxFactoryClassName);
			getLogger().debug("LDAP security protocol: {}", securityProtocol);
			getLogger().debug("LDAP security authentication: {}", securityAuthentication);
			getLogger().debug("LDAP referrals: {}", referral);
		}

        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.PROVIDER_URL, providerUrl);
        env.put(Context.INITIAL_CONTEXT_FACTORY, ctxFactoryClassName);
        if (username != null) {
            env.put(Context.SECURITY_PRINCIPAL, username);
        }
        if (password != null) {
            env.put(Context.SECURITY_CREDENTIALS, password);
        }
        if (securityProtocol != null) {
        	env.put(Context.SECURITY_PROTOCOL, securityProtocol);
        }
        if (securityAuthentication != null) {
        	env.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);
        }
        if (referral != null) {
        	env.put(Context.REFERRAL, referral);
        }

        return new InitialLdapContext(env, null);
	}

	public LdapContext getSystemLdapContext() throws NamingException {
		String principal = this.configuration.getSecurityPrincipal();
		String credentials = this.configuration.getSecurityCredentials();
		if (getLogger().isDebugEnabled()) {
			if (principal != null) {
				getLogger().debug("LDAP security principal: {}", principal);
			} else {
				getLogger().debug("LDAP security principal not set");
			}
			if (credentials	!= null) {
				getLogger().debug("LDAP security credentials: **********");
			} else {
				getLogger().debug("LDAP security credentials not set");
			}
		}
        return getLdapContext(principal, credentials);
	}
}
